package com.pai4j.ugc.schedule;

import com.pai4j.common.enums.MessageQueueTaskStatusEnum;
import com.pai4j.common.util.JsonUtil;
import com.pai4j.domain.vo.response.moment.AiContent;
import com.pai4j.ugc.repository.dao.IMessageQueueTaskDAO;
import com.pai4j.ugc.repository.dao.IMomentAiContentDAO;
import com.pai4j.ugc.repository.dao.IMomentAiKeywordDAO;
import com.pai4j.ugc.repository.entity.MessageQueueTask;
import com.pai4j.ugc.repository.entity.MomentAiContentEntity;
import com.pai4j.ugc.repository.entity.MomentAiKeywordEntity;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class AiContentRetrySchedule {

    @Resource
    private IMessageQueueTaskDAO messageQueueTaskDAO;
    @Resource
    private IMomentAiContentDAO momentAiContentDAO;
    @Resource
    private IMomentAiKeywordDAO momentAiKeywordDAO;

    // 每5分钟扫描一次失败记录进行重放
    // 最大重试次数与退避策略（指数退避：初始10s，倍数2，上限30分钟）
    private static final int MAX_RETRY = 5;
    private static final long INITIAL_BACKOFF_MS = 10_000L;
    private static final long MAX_BACKOFF_MS = 30 * 60_000L;

    @Scheduled(cron = "0 */2 * * * ?")
    public void replayFailedAiContentPersists() {
        try {
            Page<MessageQueueTask> page = messageQueueTaskDAO.findAllByStatus(MessageQueueTaskStatusEnum.ERROR.getStatus(), PageRequest.of(0, 200));
            List<MessageQueueTask> tasks = page.getContent();
            long now = System.currentTimeMillis();
            for (MessageQueueTask task : tasks) {
                if (!"ai_content_persist_retry".equals(task.getTopicName())) {
                    continue;
                }
                try {
                    Map<String, Object> payload = JsonUtil.fromJson(task.getTaskJson(), Map.class);
                    Integer retryCount = payload.get("retryCount") == null ? 0 : ((Number)payload.get("retryCount")).intValue();
                    Long nextRetryTsMs = payload.get("nextRetryTsMs") == null ? 0L : ((Number)payload.get("nextRetryTsMs")).longValue();
                    if (nextRetryTsMs > now) {
                        continue; // 未到重试时间
                    }

                    Long momentId = ((Number) payload.get("momentId")).longValue();
                    Map<String, Object> aiContentMap = (Map<String, Object>) payload.get("aiContent");
                    AiContent aiContent = JsonUtil.fromJson(JsonUtil.toJsonString(aiContentMap), AiContent.class);

                    // upsert ai content
                    MomentAiContentEntity entity = momentAiContentDAO.findByMomentId(momentId).orElse(new MomentAiContentEntity());
                    entity.setMomentId(momentId);
                    entity.setQualityScore(aiContent.getQualityScore());
                    entity.setSentiment(aiContent.getSentiment());
                    entity.setKeywords(JsonUtil.toJsonString(aiContent.getKeywords()));
                    entity.setSummary(aiContent.getSummary());
                    momentAiContentDAO.save(entity);

                    // rebuild keyword index
                    momentAiKeywordDAO.deleteByMomentId(momentId);
                    if (aiContent.getKeywords() != null) {
                        for (String kw : aiContent.getKeywords()) {
                            if (kw != null && !kw.isBlank()) {
                                MomentAiKeywordEntity e = new MomentAiKeywordEntity();
                                e.setMomentId(momentId);
                                e.setKeyword(kw.trim());
                                momentAiKeywordDAO.save(e);
                            }
                        }
                    }

                    // 标记成功
                    task.setStatus(MessageQueueTaskStatusEnum.SUCCESS.getStatus());
                    task.setUpdateDate(new Date());
                    messageQueueTaskDAO.save(task);
                } catch (Exception ex) {
                    // 失败退避重试
                    try {
                        Map<String, Object> payload = JsonUtil.fromJson(task.getTaskJson(), Map.class);
                        Integer retryCount = payload.get("retryCount") == null ? 0 : ((Number)payload.get("retryCount")).intValue();
                        retryCount++;
                        payload.put("retryCount", retryCount);
                        if (retryCount >= MAX_RETRY) {
                            payload.put("exhausted", true);
                            task.setStatus(MessageQueueTaskStatusEnum.EXHAUSTED.getStatus());
                        }
                        long backoff = Math.min(MAX_BACKOFF_MS, (long)(INITIAL_BACKOFF_MS * Math.pow(2, Math.max(0, retryCount - 1))));
                        payload.put("nextRetryTsMs", System.currentTimeMillis() + backoff);
                        task.setTaskJson(JsonUtil.toJsonString(payload));
                        task.setUpdateDate(new Date());
                        messageQueueTaskDAO.save(task);
                    } catch (Exception wrap) {
                        log.error("重试信息写回失败，taskId={}", task.getTaskId(), wrap);
                    }
                }
            }
        } catch (Exception e) {
            log.error("扫描AI内容重试任务失败", e);
        }
    }
}

